#!/usr/bin/env python3

import json
import os
from sys import exit
import subprocess
import xml.etree.ElementTree as ET
import re


def fix_formatting(ET, root):
    # fix the formatting by hand, because this project has enough
    # dependencies already
    lines = ET.tostring(root, encoding="unicode").splitlines()

    lines[-2] = lines[-2].replace("><", ">\n<")

    parts = lines[-2].splitlines()

    if len(parts) > 1:
        indent = " " * 4
        double_ident = indent * 2

        for i in range(0, len(parts) - 1):
            parts[i] = parts[i].replace(indent, indent * 2)

        parts[-1] = indent + parts[-1]

    lines[-2] = "\n".join(parts)

    with open("qml.qrc", "w") as f:
        f.write("\n".join(lines))
        f.write("\n")


def update_qrc(src_to_dest, foundation_files):
    # start updating the qml.qrc file
    with open("qml.qrc") as f:
        root = ET.fromstring(f.read())

    qrc_mjs_files = set()
    mjs_pattern = re.compile(r".*\.mjs")

    for file_name in root.iter("file"):
        inner_text = next(file_name.itertext())
        if (inner_text is not None) and mjs_pattern.match(inner_text):
            qrc_mjs_files.add(inner_text)

    qresource = next(root.iter("qresource"))

    # only deal with files not already tracked, and not already exported through foundation
    diff = (
        set(src_to_dest.values()).difference(qrc_mjs_files).difference(foundation_files)
    )

    for file in qrc_mjs_files:
        print("Skipping:", file)

    for file in diff:
        print("Adding:", file)
        file_elem = ET.SubElement(qresource, "file")
        file_elem.text = file

    fix_formatting(ET, root)


def rename_files(src_to_dest):
    for src, dest in src_to_dest.items():
        # use `renames` rather than `rename` so intermediate
        # directories are created as needed
        os.renames(src, dest)


def main():
    # get list of typescript files
    with open("tsconfig.json") as f:
        tsconfig = json.load(f)
        tsfiles = tsconfig["files"]

    # pattern to extract groups from paths
    ts_pattern = re.compile(r"(.*)(\/ts\/)(.*)(\.ts)")
    tsd_pattern = re.compile(r"(.*)(\/ts\/)(.*)(\.d\.ts)")

    foundation_pattern = re.compile(r"(.*)\/foundation\/(.*)")

    # this is a mapping from the *.js files generated by TS,
    # and the *.mjs files needed by QML. Unforuntaley, tsc cannot
    # produce *.mjs files right now
    src_to_dest = dict()
    foundation_files = set()

    for file in set(tsfiles):
        tsd_match = tsd_pattern.match(file)

        if tsd_match is not None:
            # ignore TypeScript declaration files
            continue

        ts_match = ts_pattern.match(file)

        # enforce clean directory structure
        if (ts_match is None) and (tsd_match is None):
            print(
                "Error: TypeScript files must be in `ts` subdirectories, but",
                file,
                "was not",
            )
            exit(1)

        src_js_parts = list(ts_match.groups())
        src_js_parts[-1] = ".js"
        src_js_file = "".join(src_js_parts)

        dest_js_parts = list(ts_match.groups())
        dest_js_parts[-3] = "/js/"
        dest_js_parts[-1] = ".mjs"
        dest_js_file = "".join(dest_js_parts)
        src_to_dest[src_js_file] = dest_js_file

        foundation_match = foundation_pattern.match(file)

        if foundation_match is not None:
            print("Skipping: ", dest_js_file)
            foundation_files.add(dest_js_file)

    # run the compiler
    subprocess.run(["../node_modules/typescript/bin/tsc"], shell=True, check=True)

    rename_files(src_to_dest)
    update_qrc(src_to_dest, foundation_files)


if __name__ == "__main__":
    main()
